home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * (a) (C) 1990 by Adobe Systems Incorporated. All rights reserved.
- *
- * (b) If this Sample Code is distributed as part of the Display PostScript
- * System Software Development Kit from Adobe Systems Incorporated,
- * then this copy is designated as Development Software and its use is
- * subject to the terms of the License Agreement attached to such Kit.
- *
- * (c) If this Sample Code is distributed independently, then the following
- * terms apply:
- *
- * (d) This file may be freely copied and redistributed as long as:
- * 1) Parts (a), (d), (e) and (f) continue to be included in the file,
- * 2) If the file has been modified in any way, a notice of such
- * modification is conspicuously indicated.
- *
- * (e) PostScript, Display PostScript, and Adobe are registered trademarks of
- * Adobe Systems Incorporated.
- *
- * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
- * CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
- * AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
- * ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
- * OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
- * WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
- * WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
- * DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
- * OF THIRD PARTY RIGHTS.
- */
-
- /*
- * DrawingView.m
- *
- * This view represents the page that the image is drawn onto. It is
- * a subview of the DocView. The DocView is the document view of
- * the ClipView. This view's real size grows with the scale but the
- * bounds always stays the same.
- *
- * Version: 2.0
- * Author: Ken Fromm
- * History:
- * 03-07-91 Added this comment.
- */
-
- #import "DrawingView.h"
- #import "DrawingViewWraps.h"
- #import "DocView.h"
- #import "TextApp.h"
-
- #import "hdshowaux.h"
-
- #import <appkit/Button.h>
- #import <appkit/Cell.h>
- #import <appkit/Font.h>
- #import <appkit/Matrix.h>
- #import <appkit/nextstd.h>
-
- #import <dpsclient/dpsclient.h>
- #import <dpsclient/wraps.h>
-
- #import <ctype.h>
-
- extern char*const textstrings[];
- extern float textstart[][2];
-
- @implementation DrawingView
-
- /*
- * Allocate a gstate, set the clipping to NO because it will be clipped
- * by the clip view.
- */
- +newFrame:(NXRect *) frm
- {
- id font;
-
- self = [super newFrame:frm];
-
- [[[self allocateGState] setClipping:NO] setFlipped:YES];
- NX_MALLOC(charspace, NXCoord, MAX_XSHOW);
- AllocShowStruct(&s);
-
- showtype = XSHOW; /* use xshow */
- cache = YES; /* use font cache */
-
- fontsize = FONTSIZE;
- font = [Font newFont:"Times-Roman" size:fontsize];
- PSWCopyFont("Times-Roman", "Times-RomanOutline");
-
- PSWCurrentcacheparams(&size, &lower, &upper);
-
- return self;
- }
-
- - free
- {
- PSWSetcacheparams(size, lower, upper);
- NXPing();
-
- NX_FREE(charspace);
- FreeShowStruct(&s);
-
- return [super free];
- }
-
- - (int) rotation
- {
- return rotation;
- }
-
- - fontsize:sender
- {
- fontsize = atof([[sender selectedCell] title]);
-
- [self reshow:self];
-
- return self;
- }
-
- - justify:sender
- {
- justify = ([sender selectedTag] != 0);
- [self reshow:self];
-
- return self;
- }
-
- - kern:sender
- {
- kern = [[sender selectedCell] state];
- [self reshow:self];
-
- return self;
- }
-
- - track:sender
- {
- track = [[sender selectedCell] state];
- [self reshow:self];
-
- return self;
- }
-
- /*
- * Sets the font cache to an arbitrarily low size. It's almost never necessary
- * to change the font cache size. This is only here to provide some
- * demonstration of the effectiveness of the font cache. Its operation is
- * best left alone.
- */
- - cache:sender
- {
- cache = [[sender selectedCell] state];
- if (cache)
- PSWSetcacheparams(size, lower, upper);
- else
- PSWSetcacheparams(0, 0, 0);
-
- [self reshow:self];
-
- return self;
- }
-
- - outline:sender
- {
- outline = [[sender selectedCell] state];
- [self reshow:self];
-
- return self;
- }
-
- - show:sender
- {
- showtype = [sender selectedTag];
- [self reshow:self];
-
- return self;
- }
-
- - compareKerns:sender
- {
- id cell;
-
- compareKern = [[sender selectedCell] state];
- if (compareKern && compareWidths)
- {
- compareWidths = NO;
- cell = [[NXApp comparisonsMatrix] findCellWithTag:WIDTH_TAG];
- [cell setState:NO];
- [[cell controlView] drawCell:cell];
- }
-
- [self reshow:self];
-
- return self;
- }
-
- - compareWidths:sender
- {
- id cell;
-
- compareWidths = [[sender selectedCell] state];
- if (compareWidths && compareKern)
- {
- compareKern = NO;
- cell = [[NXApp comparisonsMatrix] findCellWithTag:KERN_TAG];
- [cell setState:NO];
- [[cell controlView] drawCell:cell];
- }
-
- [self reshow:self];
-
- return self;
- }
-
- - rotate:sender
- {
- id field;
-
- field = [NXApp rotationField];
-
- if (sender == field)
- rotation = atoi([field stringValue]);
- else if ([sender selectedTag] == 0)
- rotation += ROTATION;
- else
- rotation -= ROTATION;
-
- rotation = rotation % 360;
- [field setIntValue:rotation];
-
- [self resetFields:self];
- [self rotateTo:(float) rotation];
- [superview rotateDrawView];
- [self displayFields:self];
-
- return self;
- }
-
- /*
- * Changes the title of the menu cell according
- * to the value of the trace variable.
- */
- -trace:sender
- {
- if (trace == NO)
- [[sender selectedCell] setTitle:"Trace On"];
- else
- [[sender selectedCell] setTitle:"Trace Off"];
-
- trace = !trace;
-
- return self;
- }
-
- - eraseFields:sender
- {
- id matrixId;
-
- int i;
-
- matrixId = [NXApp timingMatrix];
- for (i= 0; i < [matrixId cellCount]; i++)
- [[matrixId cellAt:i :0] setStringValue:""];
-
- matrixId = [NXApp statusMatrix];
- for (i= 0; i < [matrixId cellCount]; i++)
- [[matrixId cellAt:i :0] setStringValue:""];
-
- eraseFields = NO;
-
- return self;
- }
-
- - resetFields:sender
- {
- /* Prepare for next time around. */
- timing_info.chars = timing_info.reshows = timing_info.kerns = timing_info.time = 0;
-
- return self;
- }
-
- - displayFields:sender
- {
- id matrixId;
-
- int i, cvalues[7];
-
- if (timing_info.reshows)
- {
- matrixId = [NXApp timingMatrix];
- [[matrixId cellAt:0 :0] setIntValue:rint(timing_info.time/timing_info.reshows)];
- [[matrixId cellAt:1 :0] setIntValue:rint(timing_info.chars/timing_info.reshows)];
- [[matrixId cellAt:2 :0] setIntValue:rint(timing_info.kerns/timing_info.reshows)];
-
- matrixId = [NXApp statusMatrix];
- PSWCachestatus(cvalues);
- for (i= 0; i < [matrixId cellCount]; i++)
- [[matrixId cellAt:i :0] setIntValue:cvalues[i]];
-
- }
-
- [self resetFields:self];
- eraseFields = YES;
-
- return self;
- }
-
- - reshow:sender
- {
- NXRect visRect;
-
- eraseFields = NO;
-
- [self resetFields:self];
- [self getVisibleRect:&visRect];
- [self display:&visRect :1];
-
- [self displayFields:self];
-
- return self;
- }
-
- /*
- * If the docview is zooming, then scale the drawing view.
- */
- - mouseDown:(NXEvent *)event
- {
- NXPoint p;
-
- p = event->location;
- if ([superview isZooming])
- {
- eraseFields = NO;
- [self resetFields:self];
- [superview scaleDrawViewToPoint:&p];
- [self displayFields:self];
- }
-
- return self;
- }
-
- static NXCoord filltrackwidths(char *str, float *array, ShowStruct *s, float value)
- {
- int i, len;
-
- NXCoord trackwidth = 0.0;
-
- if (str && value)
- {
- len = strlen(str);
- if (array)
- {
- for (i = 0; i < len; i++)
- array[i] += value;
- }
- else if (s)
- AddTracking(s, 0, value);
-
- trackwidth = len * value;
- }
-
- return trackwidth;
- }
-
- static void fillspacewidths(char *str, float *array, ShowStruct *s, float value)
- {
- int i, len;
-
- if (str && value)
- {
- if (array)
- {
- len = strlen(str);
- for (i = 0; i < len; i++)
- if (str[i] == ' ')
- array[i] += value;
- }
- else if (s)
- AddSpaceAdj(s, 0, value);
- }
- }
-
- /*
- * If an array is passed in then place the character width for each character
- * in str in it (used when displaying with xshow). Also keep track of the total width
- * and the number of spaces and return the value of the width divided by the
- * spaces (used when displaying with full justification).
- */
- static NXCoord fillstringwidths(char *str, NXFontMetrics *metrics, float *array, float fontsize, NXCoord kernwidth, NXCoord trackwidth)
- {
- BOOL nospacing = NO;
-
- int i, len,
- spaces;
-
- NXCoord value,
- linewidth;
-
- spaces = 0;
- linewidth = kernwidth + trackwidth;
- if (str && metrics && metrics->widths)
- {
- len = strlen(str);
- for (i = 0; i < len; i++)
- {
- value = metrics->widths[(unsigned char)str[i]] * fontsize;
- linewidth += value;
- if (array)
- array[i] += value;
-
- /* Check for space, return, linefeed, etc. */
- if(isspace(str[i]))
- {
- if (str[i] == ' ')
- spaces ++;
- else
- nospacing = YES;
- }
- }
- }
-
- if (spaces == 0)
- value = 0.0;
- else
- {
- if (trackwidth)
- value = (LINE_LENGTH_TR - linewidth)/spaces;
- else
- value = (LINE_LENGTH - linewidth)/spaces;
- if (nospacing && value > 0)
- value = 0.0;
- }
-
- return value;
- }
-
- /*
- * Look up the kern pairs for the first character and see if
- * there is an entry for the second character. Returns the
- * value to kern if any.
- */
- static NXCoord getkernvalue(NXFontMetrics *metrics, unsigned char char1, unsigned char char2)
- {
- int enc1, enc2,
- i, kindex, klen;
-
- NXCoord value = 0.0;
-
- enc1 = metrics->encoding[char1];
- enc2 = metrics->encoding[char2];
- if (enc1 < metrics->numCharMetrics && enc2 < metrics->numCharMetrics)
- {
- kindex = metrics->charMetrics[enc1].kernPairIndex;
- klen = metrics->charMetrics[enc1].numKernPairs;
- if (kindex+klen < metrics->numKernPairs)
- {
- for (i = kindex; i < kindex + klen; i++)
- {
- if (metrics->hasXYKerns)
- {
- if (enc2 == metrics->kerns.kernPairs[i].secondCharIndex)
- {
- value = metrics->kerns.kernPairs[i].dx;
- break;
- }
- }
- else
- {
- if (enc2 == metrics->kerns.kernXPairs[i].secondCharIndex)
- {
- value = metrics->kerns.kernXPairs[i].dx;
- break;
- }
- }
- }
- }
- }
-
- return value;
- }
-
- static NXCoord fillkernwidths(char *str, NXFontMetrics *metrics, float *array, ShowStruct *s, float fontsize, int *kerns)
- {
- int i, len;
-
- NXCoord value,
- kernwidth;
-
- kernwidth = 0.0;
- if (str && metrics)
- {
- len = strlen(str) -1;
- for (i = 0; i < len; i++)
- {
- if (value = getkernvalue(metrics, (unsigned char) str[i], (unsigned char) str[i+1]))
- {
- value = value * fontsize;
- if (array)
- array[i] += value;
- else if (s)
- AddPairKern(s, i+1, value);
-
- kernwidth += value;
- (*kerns)++;
- }
- }
- }
-
- return kernwidth;
- }
-
- /*
- * Go through the line and insert the appropriate value into the array.
- * The value placed in is dependent on whether we are kerning or not
- * and whether we are using xshow or not. If kerning, then look up each
- * pair in the AFM kerning array. If using xshow, then include the
- * character width in the array as well (xshow takes the displacement from
- * the previously shown character hence the character width).
- * The fontsize is used to scale the kerning value and the character width.
- * In a screenfont, no adjustment is necessary because the values are
- * already scaled to the appropriate values.
- */
- static int characterspacing(id font, char *str, NXCoord *array, BOOL justify, BOOL kern, BOOL track, BOOL width)
- {
- int kerns = 0;
-
- float fontsize;
-
- NXCoord kernwidth,
- spacewidth,
- trackwidth;
-
- NXFontMetrics *metrics;
-
- bzero(array, MAX_XSHOW*sizeof(NXCoord));
-
- metrics = [font readMetrics:FONTMETRICS];
- if (metrics)
- {
- if (metrics->isScreenFont)
- fontsize = 1;
- else
- fontsize = [font pointSize];
-
- kernwidth = spacewidth = trackwidth = 0.0;
-
- if (kern && metrics->encoding && metrics->charMetrics)
- kernwidth = fillkernwidths(str, metrics, array, NULL, fontsize, &kerns);
-
- if (track)
- trackwidth = filltrackwidths(str, array, NULL, TRACKVAL);
-
- if (width && metrics->widths)
- spacewidth = fillstringwidths(str, metrics, array, fontsize, kernwidth, trackwidth);
-
- if (justify)
- {
- if (!width && metrics->widths)
- spacewidth = fillstringwidths(str, metrics, NULL, fontsize,
- kernwidth, trackwidth);
- fillspacewidths(str, array, NULL, spacewidth);
- }
- }
-
- return kerns;
- }
-
- static int showstructure(id font, char *str, ShowStruct *s, BOOL justify, BOOL kern, BOOL track)
- {
- int kerns = 0;
-
- float fontsize;
-
- NXCoord kernwidth,
- spacewidth,
- trackwidth;
-
- NXFontMetrics *metrics;
-
- metrics = [font readMetrics:FONTMETRICS];
- if (metrics)
- {
- if (metrics->isScreenFont)
- fontsize = 1;
- else
- fontsize = [font pointSize];
-
- kernwidth = spacewidth = trackwidth = 0.0;
- if (kern && metrics->encoding && metrics->charMetrics)
- kernwidth = fillkernwidths(str, metrics, NULL, s, fontsize, &kerns);
-
- if (track)
- trackwidth = filltrackwidths(str, NULL, s, TRACKVAL);
-
- if (justify)
- {
- spacewidth = fillstringwidths(str, metrics, NULL, fontsize, kernwidth, trackwidth);
- fillspacewidths(str, NULL, s, spacewidth);
- }
-
- }
-
- return kerns;
- }
-
- /*
- * Set the font either to the printer font or the screenfont, turn the trace on
- * if tracing and then mark the time. (The last two steps are for demonstration
- * purposes only. Cycle through the static array of text checking if a line
- * intersects the rectangle passed in. If so then draw it according to the values
- * set in the interface - kerning or no kerning, screen widths or printer widths,
- * xshow or rmoveto/show, etc.
- */
- - showText:(const NXRect *)r
- {
- id font;
-
- float x;
-
- int i, j, last,
- chars,
- ElapsedTime;
-
- NXRect textRect;
-
- if (trace)
- DPSTraceContext(DPSGetCurrentContext(), YES);
-
- font = [Font newFont:"Times-Roman" size:fontsize];
- if (outline)
- PSWSetFont("Times-RomanOutline", fontsize);
- else
- [font set];
-
- if (screen && [font screenFont])
- font = [font screenFont];
-
- textRect.origin.x = bounds.origin.x;
- textRect.size.width = bounds.size.width;
- textRect.size.height = 2 * fontsize;
-
- PSsetwindowtype(NX_RETAINED, [window windowNum]);
- PSWMarkTime(); NXPing();
- for (i = 0; i < NUM_LINES; i++)
- {
- textRect.origin.y = textstart[i][1] - fontsize;
- if (NXIntersectsRect(r, &textRect))
- {
- chars = strlen(textstrings[i]);
- timing_info.chars += chars;
- if (showtype == XSHOW || showtype == RMSHOW)
- {
- timing_info.kerns += characterspacing(font, textstrings[i], charspace, justify,
- kern, track, (showtype == XSHOW));
- if (showtype == XSHOW)
- {
- PSmoveto(textstart[i][0], textstart[i][1]);
- PSxshow(textstrings[i], charspace, chars);
- }
- else
- {
- PSmoveto(textstart[i][0], textstart[i][1]);
- for (j = 0, last = -1, x = 0.0; j < chars; j++)
- {
- if (charspace[j] != 0)
- {
- if (x == 0.0)
- PSWShow(&textstrings[i][last+1], j - last);
- else
- PSWRmovetoShow(x, &textstrings[i][last+1], j - last);
- last = j;
- x = charspace[j];
- }
- }
- if (x == 0.0)
- {
- if (j-last > 0)
- PSWShow(&textstrings[i][last+1], j - last);
- }
- else
- {
- if (j-last-1 > 0)
- PSWRmovetoShow(x, &textstrings[i][last+1], j - last -1);
- }
- }
- }
- else
- {
- ResetShowStruct(&s);
- AddString(&s, textstrings[i]);
- AddMoveto(&s, 0, textstart[i][0], textstart[i][1]);
- timing_info.kerns += showstructure(font, textstrings[i], &s, justify,
- kern, track);
- ShowAny(&s);
- }
- }
- }
- PSWReturnTime(&ElapsedTime);
- if (trace)
- DPSTraceContext(DPSGetCurrentContext(), NO);
- PSsetwindowtype(NX_BUFFERED, [window windowNum]);
-
- timing_info.time += ElapsedTime;
- timing_info.reshows++;
-
- return self;
- }
-
- /*
- * Erase the fields in the interface, whiten the backdrop, check the cases
- * for showing the text and call the showText: method appropriately.
- */
- - drawSelf:(const NXRect *)r :(int) count
- {
- BOOL temp;
-
- if (eraseFields)
- [self eraseFields:self];
-
- PSsetgray(NX_WHITE);
- NXRectFill(r);
- PSsetgray(NX_BLACK);
-
- if (track)
- PStranslate(-45, 0);
-
- if (compareKern)
- {
- temp = kern;
- kern = YES;
- [self showText:r];
-
- kern = NO;
- PStranslate(0.0, 10.0);
- [self showText:r];
- kern = temp;
- }
- else if (compareWidths)
- {
- temp = screen;
- screen = NO;
- [self showText:r];
-
- screen = YES;
- PStranslate(0.0, 10.0);
- [self showText:r];
- screen = temp;
- }
- else
- [self showText:r];
-
- return self;
- }
-
- @end
-